package com.yyfax.pay.common.util;

import java.lang.reflect.Field;
import java.util.Collection;
import java.util.List;

import org.apache.commons.lang3.StringUtils;
import org.springframework.util.ReflectionUtils;
import org.springframework.util.ReflectionUtils.FieldCallback;

import com.google.common.collect.Lists;
import com.yyfax.framework.exception.YYException;
import com.yyfax.framework.yyfax.YYFaxSignUtil;
import com.yyfax.pay.common.annotation.CheckSignIngore;
import com.yyfax.pay.common.model.to.YYPayParams;
import com.yyfax.pay.vo.depository.EBankChargeReq;

/**
 * 签名工具类
 * 
 * @author maojian
 */
public class CheckSignUtils {

	public interface FieldCallbacks extends FieldCallback {
		void doWith(Field arg0);
	}

	static class CheckSignException extends RuntimeException {
		public CheckSignException(String message) {
			super();
		}
	}

	/**
	 * 获取所有属性及签名
	 * 
	 * @param param
	 * @param key
	 * @return
	 */
	private static String[] getAllCheckSignFields(YYPayParams param, String key) {
		final YYPayParams paramF = param;
		final String keyF = key;
		final List<String> fieldList = Lists.newArrayList();
		ReflectionUtils.doWithLocalFields(param.getClass(), new FieldCallbacks() {
			@Override
			public void doWith(Field arg0) {
				CheckSignIngore anno = arg0.getAnnotation(CheckSignIngore.class);
				if (anno != null) {
					return;
				}
				if (Collection.class.isAssignableFrom(arg0.getType()) && YYPayParams.class.isAssignableFrom(arg0.getDeclaringClass())) {
					arg0.setAccessible(true);
					Collection<YYPayParams> child = (Collection<YYPayParams>) ReflectionUtils.getField(arg0, paramF);
					for (YYPayParams childP : child) {
						if (!checkSign(childP, keyF, childP.getSign())) {
							throw new CheckSignException("验签失败");
						}
					}
				} else {
					fieldList.add(arg0.getName());
				}
			}
		});
		return fieldList.toArray(new String[fieldList.size()]);
	}

	/**
	 * 验证签名
	 * 
	 * @author maojian
	 * @date 2017-05-03 15:49:03
	 * @since v1.0.0
	 * @param key
	 * @return
	 * @throws YYException
	 */
	public static boolean checkSign(YYPayParams param, String key, String signValue) {
		if (StringUtils.isBlank(signValue)) {
			return false;

		}
		try {
			String realSign = sign(param, key);
			if (StringUtils.equals(realSign, signValue)) {
				return true;
			}
		} catch (Exception e) {
			return false;
		}

		return false;
	}

	/**
	 * 获取签名值
	 * 
	 * @param
	 * @param signFields
	 * @return
	 */
	public static String sign(YYPayParams param, String key) {
		return YYFaxSignUtil.md5Sign(param, key, getAllCheckSignFields(param, key));
	}

	/**
	 * 验证签名<br>
	 * 不支持循环嵌套
	 * 
	 * @author buyi
	 * @date 2017-05-24 10:36:54
	 * @since v1.0.0
	 * @param obj
	 * @param key
	 * @param signValue
	 * @return
	 */
	public static boolean checkSign2(Object obj, String key, String signValue) {
		if (StringUtils.isBlank(signValue)) {
			return false;

		}

		try {
			String realSign = sign2(obj, key);
			if (StringUtils.equals(realSign, signValue)) {
				return true;
			}
		} catch (Exception e) {
			return false;
		}

		return false;
	}

	/**
	 * 获取实体对象签名值
	 * 
	 * @author buyi
	 * @date 2017-05-24 10:12:26
	 * @since v1.0.0
	 * @param obj
	 * @param key
	 * @return
	 */
	public static String sign2(Object obj, String key) {
		return YYFaxSignUtil.md5Sign(obj, key, getCheckSignFields(obj));
	}

	/**
	 * 获取实体对象需要签名的字段
	 * 
	 * @author buyi
	 * @date 2017-05-24 10:12:32
	 * @since v1.0.0
	 * @param obj
	 * @return
	 */
	public static String[] getCheckSignFields(Object obj) {
		final List<String> fieldList = Lists.newArrayList();

		ReflectionUtils.doWithFields(obj.getClass(), new FieldCallbacks() {

			@Override
			public void doWith(Field arg0) {
				CheckSignIngore anno = arg0.getAnnotation(CheckSignIngore.class);
				if (anno != null) {
					return;
				}

				fieldList.add(arg0.getName());
			}

		});

		return fieldList.toArray(new String[fieldList.size()]);
	}

}
